import json

from flask import request, current_app
from werkzeug.exceptions import HTTPException


class APIException(HTTPException):
    code = 400
    msg = 'sorry , we get system error.'
    custom_code = '00'

    def __init__(self, code=None, msg=None, custom_code=None):
        self.code = code if code else self.code
        self.msg = msg if msg else self.msg
        self.custom_code = custom_code if custom_code else self.custom_code
        self.error_code = str(self.code) + str(self.custom_code)
        super(APIException, self).__init__(msg)

    def get_body(self, environ=None):
        """Get the json body."""
        body = dict(
            code=self.code,
            msg=self.msg,
            error_code=self.error_code,
            request=f'{request.method} {request.path}'
        )
        if self.code >= 210:
            try:
                log = {
                    "ERROR": body,
                    "BODY": request.json
                }
            except Exception:
                log = {
                    "ERROR": body
                }
            current_app.logger.error(log)
        return json.dumps(body)

    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [("Content-Type", "application/json; charset=utf-8")]


def framework_404(e):
    return NotFound()


def framework_500(e):
    if isinstance(e, APIException):
        return e
    # elif isinstance(e, HTTPException):
    #     return APIException(e.code, e.description)
    else:
        if current_app.debug:
            current_app.logger.exception(e)
            return ServerError(msg=e.__repr__())
        else:
            return ServerError()


# 200
class Success(APIException):
    code = 200
    msg = 'ok'


class Deleted(Success):
    pass


# 201
class Created(Success):
    code = 201


# 401
class Missing_Token(APIException):
    code = 401
    custom_code = '01'
    msg = 'Missing Token'


class Expired_Token(Missing_Token):
    custom_code = '02'
    msg = 'Expired Token'


class Invalid_Token(Missing_Token):
    custom_code = '03'
    msg = 'Invalid Token'


# 403
class PermissionDenied(APIException):
    code = 403
    custom_code = '01'
    msg = 'Permission Denied'


class ParameterError(PermissionDenied):
    msg = 'Parameter Error'
    custom_code = '02'


class ExistBatchImportAsset(PermissionDenied):
    custom_code = '03'
    msg = 'Exist Batch Import Asset'


class EmptyData(PermissionDenied):
    custom_code = '04'
    msg = 'Empty Data'


class AddJobError(PermissionDenied):
    custom_code = '05'
    msg = 'Add Job Error'


class UploadFileError(PermissionDenied):
    custom_code = '06'
    msg = '文件错误。'


class PackageLimit(PermissionDenied):
    custom_code = '07'
    msg = 'Package Limit'


class BalanceLimit(PermissionDenied):
    custom_code = '08'
    msg = 'Balance limit'


class PackageExpired(ParameterError):
    custom_code = '08'
    msg = '套餐过期。'


class JobNotVerified(ParameterError):
    custom_code = '09'
    msg = '资产未认证。'


class AddAlertGroupError(PermissionDenied):
    custom_code = '10'
    msg = 'Add alert_group Error'


class CustomNameError(PermissionDenied):
    custom_code = '11'
    msg = '名称格式错误，只能输入1～50个中文、英文字母、数字、下划线'


# 404
class NotFound(APIException):
    code = 404
    msg = 'Not Found'
    custom_code = '01'


class JobNotFound(NotFound):
    msg = 'Job Not Found'
    custom_code = '02'


class FileNotFound(NotFound):
    msg = 'File Not Found'
    custom_code = '03'


class TaskNotFound(NotFound):
    msg = 'Task Not Found'
    custom_code = '04'


class AssetNotFound(NotFound):
    msg = 'Asset Not Found'
    custom_code = '05'


# 500
class ServerError(APIException):
    code = 500
    msg = '系统繁忙'
    custom_code = '01'


class ScannerAPINotOk(ServerError):
    msg = 'Scanner API Not Ok'
    custom_code = '02'


class ScannerAPIException(ServerError):
    msg = 'Scanner API Exception'
    custom_code = '03'


class OMSAPIException(ServerError):
    msg = 'OMS API Exception'
    custom_code = '04'


class OMSAPINotOk(ServerError):
    msg = 'OMS API Not Ok'
    custom_code = '05'


class ScannerAPICreateTaskFail(ServerError):
    msg = 'Scanner API Create Task Fail'
    custom_code = '04'


class JobNotSyncYAQError(ServerError):
    msg = "Asset do not bind yunaq."
    custom_code = '05'


class NoticeError(ServerError):
    msg = "Accept notice error"
    custom_code = '05'


class NoticeForcedWaiting(Success):
    code = 201
    msg = 'Notice forced waiting'


class TaskNotFoundError(Exception):
    pass


class TaskError(ServerError):
    custom_code = '10'
    msg = '任务失败。'


class SEEBUGAPIException(ServerError):
    msg = 'SEEBUG API Exception'
    custom_code = '04'


class SEEBUGAPINotOk(ServerError):
    msg = 'SEEBUG API Not Ok'
    custom_code = '05'


class JobNotFoundError(ServerError):
    def __init__(self, job_id, task_pk=None, *args, **kwargs):
        self.task_id = task_pk
        super(JobNotFoundError, self).__init__(msg=f"Job id {job_id} not found", *args, **kwargs)

    msg = 'Job not found'
    custom_code = '06'


class CeleryPushError(ServerError):
    def __init__(self, task_id, *args, **kwargs):
        self.task_id = task_id
        super(CeleryPushError, self).__init__(msg=f"Task._id {task_id} can't push into celery.", *args, **kwargs)

    msg = "push into celery error"
    custom_code = '07'
